package org.folio.rest.impl.other.client.impl;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import cn.hutool.json.JSONUtil;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClient;
import org.folio.rest.RestVerticle;
import org.folio.rest.impl.other.client.OkapiUserModulesClient;
import org.folio.rest.jaxrs.model.User;
import org.folio.rest.jaxrs.model.UserdataCollection;

import javax.ws.rs.BadRequestException;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import static org.apache.http.HttpStatus.SC_BAD_REQUEST;
import static org.apache.http.HttpStatus.SC_NO_CONTENT;
import static org.apache.http.HttpStatus.SC_OK;
/**
 * @author lee
 * @Classname OkapiUserModulesClientImpl
 * @Description TODO
 * @Date 2020/6/23 13:54
 * @Created by lee
 */
public class OkapiUserModulesClientImpl implements OkapiUserModulesClient {

    private String tenant;
    private String token;
    private String okapiUrl;

    private WebClient webClient;
    private static final String OKAPI_HEADER_URL = "x-okapi-url";

    public OkapiUserModulesClientImpl(Vertx vertx, Map<String, String> okapiHeaders) {

        webClient = WebClient.create(vertx);
        tenant = okapiHeaders.get(RestVerticle.OKAPI_HEADER_TENANT);
        token = okapiHeaders.get(RestVerticle.OKAPI_HEADER_TOKEN);
        okapiUrl = okapiHeaders.get(OKAPI_HEADER_URL);
    }
    @Override
    public Future<UserdataCollection> getUserGroup(String name) {
        Future<HttpResponse<Buffer>> future = Future.future();
        webClient.getAbs("http://localhost:9130" + "/users")
                .addQueryParam("query", "( barcode == *"+name+"* and active == true )")
                .addQueryParam("limit","30" )
                .addQueryParam("offset","0" )
                .putHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
                .putHeader(RestVerticle.OKAPI_HEADER_TENANT, tenant)
                .putHeader(RestVerticle.OKAPI_HEADER_TOKEN, token)
                .send(future.completer());

        return future
                .map(responseMapper(UserdataCollection.class));

    }


    @Override
    public Future<UserdataCollection> fetchUser(String query, Integer offset, Integer limit) {
        Future<HttpResponse<Buffer>> future = Future.future();
        webClient.getAbs("http://localhost:9130" + "/users")
                .addQueryParam("query", query)
                .addQueryParam("limit",limit.toString() )
                .addQueryParam("offset",offset.toString() )
                .putHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
                .putHeader(RestVerticle.OKAPI_HEADER_TENANT, tenant)
                .putHeader(RestVerticle.OKAPI_HEADER_TOKEN, token)
                .send(future.completer());
        return future
                .map(responseMapper(UserdataCollection.class));
    }
    @Override
    public void updateUser(User user,Handler<AsyncResult< cn.hutool.http.HttpResponse  >> asyncResultHandler) {
        HttpRequest httpRequest = HttpUtil.createRequest(Method.PUT, "http://localhost:9130/users/" + user.getId());
        Map<String, String> map = new HashMap<>() ;
        map.put(HttpHeaders.ACCEPT, MediaType.WILDCARD);
        map.put(RestVerticle.OKAPI_HEADER_TENANT, tenant);
        map.put(RestVerticle.OKAPI_HEADER_TOKEN, token);
        map.put(HttpHeaders.CONTENT_TYPE,MediaType.APPLICATION_JSON);
        httpRequest =httpRequest.addHeaders(map);
        httpRequest =httpRequest.body(JSONUtil.toJsonStr(user));
        cn.hutool.http.HttpResponse response = httpRequest.executeAsync();
        asyncResultHandler.handle(Future.succeededFuture(response));

    }

    private static  <T> Function<HttpResponse<Buffer>, T> reply(Class<T> type) {
        return resp->{
            if (resp.statusCode() == SC_BAD_REQUEST) {
                throw new BadRequestException(resp.bodyAsString());
            }
            if (resp.statusCode() != SC_OK && resp.statusCode() != SC_NO_CONTENT) {
                throw new InternalServerErrorException();
            }
            return type == Void.class ? null : resp.bodyAsJson(type);
        };
    }

    @Override
    public void getUserGroupByBarcode(List<String> barcodeGroup, Handler<AsyncResult<UserdataCollection>> asyncResultHandler) {
        Future<HttpResponse<Buffer>> future = Future.future();
        if (barcodeGroup.size() ==0){

            asyncResultHandler.handle(Future.failedFuture("读者证号不能为空！"));
            return;
        }

        String queryString = "";
        long len=barcodeGroup.size();
        for (int i = 0; i < len ; i++) {

                queryString += " or barcode = \""+barcodeGroup.get(i)+"\"";

        }
        String param = "((" + queryString.substring(3,queryString.length()) + "))";

        webClient.getAbs("http://j.tcsoft.info:29130" + "/users")
                .addQueryParam("query", param)
                .putHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON)
                .putHeader(RestVerticle.OKAPI_HEADER_TENANT, tenant)
                .putHeader(RestVerticle.OKAPI_HEADER_TOKEN, token)
                .send(reply->{

                    if (reply.result().statusCode() == SC_BAD_REQUEST) {
                         asyncResultHandler.handle(Future.failedFuture(reply.result().bodyAsString()));
                         return;
                    }
                    if (reply.result().statusCode() != SC_OK && reply.result().statusCode() != SC_NO_CONTENT) {
                        asyncResultHandler.handle(Future.failedFuture("获取用户失败！"));
                        return;
                    }
                    asyncResultHandler.handle(Future.succeededFuture(reply.result().bodyAsJson(UserdataCollection.class)));
                });

    }


    private static <T> Function<HttpResponse<Buffer>, T> responseMapper(Class<T> type) {

        return response -> {
            if (response.statusCode() == SC_BAD_REQUEST) {
                throw new BadRequestException(response.bodyAsString());
            }
            if (response.statusCode() != SC_OK && response.statusCode() != SC_NO_CONTENT) {
                throw new InternalServerErrorException();
            }
            return type == Void.class ? null : response.bodyAsJson(type);
        };
    }
}
